%{

#include <boost/lexical_cast.hpp>

#include "../MAliceDriver.hpp"

class MAliceDriver;

#define YYSTYPE  yy::MAliceParser::semantic_type
#define YYTOKEN  yy::MAliceParser::token_type

#ifdef yyterminate
# undef yyterminate
#endif
#define yyterminate() return YYTOKEN::END

#ifdef yywrap
#	undef yywrap
#endif
#define yywrap() 1
#define YY_SKIP_YYWRAP

%}

/*** Flex Declarations and Options ***/

/* the manual says "somewhat more optimized" */
%option batch

/* enable scanner to generate debug output. disable this for release
 * versions. */
%option debug

/* no support for include files is planned */
%option noyywrap nounput

/* enables the use of start condition stacks */
%option stack

/* The following paragraph suffices to track locations accurately. Each time
 * yylex is invoked, the begin position is moved onto the end position. */
%{
#define YY_USER_ACTION  yylloc->columns(yyleng);
%}

%{ /*** C/C++ Declarations ***/

#include <string>

#include "MAliceScanner.hpp"

/* import the parser's token type into a local typedef */
typedef yy::MAliceParser::token      token;
typedef yy::MAliceParser::token_type token_type;

/* By default yylex returns int, we use token_type. Unfortunately yyterminate
 * by default returns 0, which is not of token_type. */
#define yyterminate() return token::END
%}

DIGIT  [0-9]
ID     ([[:alpha:]\_][[:alnum:]\_]*|[\$][[:alnum:]\_]*)

%% /*** Regular Expressions Part ***/

 /* code to place at the beginning of yylex() */
%{
    // reset location
%}

 /*** lexer rules ***/


[ \t\r] /* gobble up white-spaces */ {
    yylloc->step();
}

[\n]+ /* gobble up end-of-lines */ {
    yylloc->lines(yyleng); yylloc->step();
}


 /******************************************************************************
 * L i t e r a l s
 ******************************************************************************/

{DIGIT}+ {
		yylval->i = boost::lexical_cast<int>(string(yytext, yyleng));		
    return token::int_literal;
}

[-+]?{DIGIT}*\.?{DIGIT}+([eE][-+]?{DIGIT}+)? {
		yylval->d = boost::lexical_cast<double>(string(yytext, yyleng));		
    return token::float_literal;
}

\'[^']\' {
	yylval->c = yytext[0];
	return token::char_literal;
}


\"[^"]*\" {
	yylval->s = new string(yytext, yyleng);
	return token::string_literal;
}

"true" {
	yylval->b = true;
	return token::bool_literal;
}

"false" {
	yylval->b = false;
	return token::bool_literal;
}

"<<" {
    return token::shift_left;
}

">>" {
    return token::shift_right;
}

"<=" {
    return token::less_than_equal;
}

">=" {
    return token::greater_than_equal;
}

"==" {
    return token::equal;
}

"!=" {
    return token::not_equal;
}

"a" {
    return token::kw_a;
}

"and" {
    return token::kw_and;
}

"but" {
    return token::kw_but;
}

"Alice" {
    return token::kw_alice;
}

"became" {
    return token::kw_became;
}

"found" {
    return token::kw_found;
}

"was" {
    return token::kw_was;
}

"too" {
    return token::kw_too;
}

"ate" {
    return token::kw_ate;
}

"drank" {
    return token::kw_drank;
}

{ID} {
	yylval->s = new string(yytext, yyleng);
  return token::id;
}

. /* pass all other characters up to parser */ {
	yylval->c = yytext[0];
	return static_cast<token_type>(yytext[0]);
}

<<EOF>> { 
	static int once = 0;
	return static_cast<token_type>(once++ ? 0 : '\n');
}

%% /*** Additional Code ***/


